import struct
import json
import os,sys

# 基础变量
keywords = {
        'char': {
            '@key': 'c',
            '[]': {'@key': 's'},
            '*': {'@key': 'p'}
        },
        'signed': {
            'char': {'@key': 'b'}
        },
        'unsigned': {
            'char': {'@key': 'B'},
            'short': {'@key': 'H'},
            'int': {'@key': 'I'},
            'long': {'@key': 'L'},
            'long': {'@key': 'Q'}
        },
        'bool': {'@key': '?'},
        'short': {'@key': 'h'},
        'int': {'@key': 'i'},
        'long': {
            '@key': 'l',
            'long': {'@key': 'q'}
        },
        'float': {'@key': 'f'},
        'double': {'@key': 'd'},
        'void': {'*': {'@key': 'P'}}
    }

keywords_a = {}

def is_word(key):
    is_alnum = True
    len_k = len(key)
    if key[0].isalpha or key[0] == '_':
        if len_k > 1:
            for c in key[1:]:
                if not (c.isalnum() or c == '_'):
                    is_alnum = False
                    break
    else:
        is_alnum = False
    return is_alnum

# strc item:  结构体名字: 类型字母, 变量名
strc = {}
strcs = {}
strc_stu = []

def beg_block():
    strc_stu.append('{')
    pass

def end_block():
    sl = len(strc_stu)
    blk_id = -1
    for i in range(sl):
        if strc_stu[sl - i - 1] == '{':
            blk_id = sl - i - 1
            break;
    if blk_id >= 0:
        pops = sl - blk_id
        for i in range(pops):
            pa = strc_stu.pop(sl - i - 1)
            if blk_id == sl - i-1:
                pass
            else:
                print('blk pop > ', pa)  # sl - i - 1,
        strc_stu.append('{}')

    else:
        print('blk error: can\'t find block begin')

def beg_array():
    strc_stu.append('[')
    pass

def end_array():
    sl = len(strc_stu)
    ary_id = -1
    for i in range(sl):
        if strc_stu[sl - i - 1] == '[':
            ary_id = sl - i - 1
            break
    # print(ary_id)
    tl = []
    if ary_id >= 0:
        pops = sl - ary_id
        for i in range(pops):
            pa = strc_stu.pop(sl - i - 1)
            
            if ary_id == sl - i-1:
                pass
            else:
                tl.append(pa)
        strc_stu.append('[]')
        strc_stu.append(tl)
    else:
        print('ary error: can\'t find array begin')

# 逗号
def sym_dou():
    sl = len(strc_stu)
    for i in range(sl):
        pi = sl - i - 1;
        if strc_stu[pi] in ['(', '[', '{']:
            break
        pa = strc_stu.pop(pi)
        print('dou pop > ', pa)
    return pa

# 分号，c语言中，语句都是用分号结束，所以这里来做语法分析
def sym_fen():
    global strc
    sl = len(strc_stu)
    tl = []
    tl_i = 0
    karry_i, kblock_i, kcb_i = [],[],[]
    for i in range(sl):
        pi = sl - i - 1
        if strc_stu[pi] in ['(', '[', '{']:
            break
        pa = strc_stu.pop(pi)
        tl.append(pa)
        if pa == '[]':
            karry_i.append(tl_i)
        elif pa == '{}':
            kblock_i.append(tl_i)
        elif pa == '()':
            kcb_i.append(tl_i)
        tl_i += 1
        
    ltl = len(tl)
    ks = keywords
    ts = []
    i = 0
    while i < ltl:
        k_i = ltl - i - 1
        k = tl[k_i]
        if isinstance(k,list): # 数组，不用管
            pass
        elif k == 'struct': 
            # 这里暂时不讨论 typedef 关键字
            # 如果 {} 和 struct 关键字 之间没得 变量名
            if len(kblock_i) > 0:
                if k_i - 1 == kblock_i[-1]:
                    kblock_i.pop(-1)
                    # 不是定义 结构类型 退出
                elif k_i - 2 == kblock_i[-1]:
                    if 'struct' not in keywords:
                        keywords['struct'] = {}
                        keywords_a['struct'] = {}
                    type_e = ''
                    args_e = {}  # 做数据数据解析的时候可能有帮助
                    for t in strc:
                        type_e += strc[t][0]

                        # 保存结构信息
                        if len(strc[t]) == 1:
                            args_e[t] = strc[t][0]
                        elif len(strc[t]) == 2:
                            args_e[t] = strc[t][1]
                        else:
                            print('type arg error!')

                    strc = {}
                    keywords['struct'][tl[k_i - 1]] = {}
                    keywords['struct'][tl[k_i - 1]]['@key'] = type_e
                    keywords['struct'][tl[k_i - 1]]['@arg'] = args_e
                    keywords_a['struct'][tl[k_i - 1]] = keywords['struct'][tl[k_i - 1]]
                kblock_i.pop(-1)
                ts = []
                break
            elif 'struct' in keywords and tl[k_i - 1] in keywords['struct']:
                ks = keywords['struct'][tl[k_i - 1]]
                i += 1
            else:
                print('struct 关键字 不是定义数据类型，退出该语句分析: ', tl)
            ts = []
        elif k == 'enum':
            print('add > ',k)
            strc_stu.append(k)
        elif k == 'union':
            print('add > ',k)
        elif k in ks:  # 数据类型结构体类型
            ks = ks[k]
        else:  # 处理数据类型
            if k == '[]':
                pass
            elif '@key' in ks:  # 数据类型
                # 多维 在这里改， 但是目前 struct 不能体现出多维数组的效果， 建议还是一维， 防止误会
                if len(karry_i) > 0 \
                        and len(tl[karry_i[-1]-1]) == 1 and tl[karry_i[-1]-1][0].isdigit():
                    kn = tl[karry_i[-1] - 1][0]
                    karry_i.pop(-1)
                elif len(karry_i) == 0:
                    kn = ''
                else:
                    print('数组目前只支持一维的整数类型，如 1， 2，3')

                # 如果是复杂的结构体数组，只能重复，用不能用数字直接标识结构体数组的大小
                if len(ks['@key']) == 1:
                    strc[k] = [kn + ks['@key']]
                else:
                    kn = int(kn) if kn.isdigit() else 1

                    strc[k] = [ks['@key'] * int(kn)]
                    if '@arg' in ks:
                        strc[k].append([ks['@arg']]*kn)

            else:
                ts.append(k)
                print('数据错误 >   \033[1;36m', ts,  '\033[0m')
        i += 1
    return pa

# 小括号
def beg_cb(): 
    pass

def end_cb():
    pass

# 等号处理
def sym_deng():
    pass

# 代码符号处理
sybs = {
    '{': beg_block,
    '}': end_block,
    '[': beg_array,
    ']': end_array,
    ',': sym_dou,
    ';': sym_fen,
    '(': beg_cb,
    ')': end_cb,
    '=': sym_deng
}

def deal_symbol(sym):
    sybs[sym]()

# 代码分割
def deal_strc(key):
    if key == 'struct':
        strc_stu.append(key)
    elif key == 'enum':
        strc_stu.append(key)
    elif key == 'union':
        strc_stu.append(key)
    elif key in keywords:
        strc_stu.append(key)
    elif key.isdigit():
        strc_stu.append(key)
    elif key in sybs:
        deal_symbol(key)
    elif is_word(key):
        strc_stu.append(key)
    else:
        print(8, key)

if __name__ == "__main__":
    file_name = '../data/a.h'
    if len(sys.argv) >= 2:
        file_name = sys.argv[1]
    # 代码初步分割
    with open(file_name) as fr:
        data = fr.read()

    str_w = data.split()
    for s in str_w:
        if s.isalnum():
            deal_strc(s)
            pass
        elif len(s) == 1:
            deal_strc(s)
        else:
            st = ''
            for c in s:
                if c.isalnum() or c == '_':
                    st += c
                else:
                    if st != '':
                        deal_strc(st)
                    deal_strc(c)
                    st = ''
            if st != '':
                deal_strc(st)

    # 打印结构变量
    print(json.dumps(keywords_a, indent=4))
    with open('%s.json' % (os.path.splitext(file_name)[0]), 'w') as fw:
        json.dump(keywords_a, fw, indent=4)
